package cn.blnp.net.flowable.ext.child.event;

import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.filter.SimplePropertyPreFilter;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.*;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ExecutionQuery;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.job.api.Job;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <h3>子流程-事件子流程</h3>
 *
 * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
 * @version 1.0
 * @since 2025/5/20 10:25
 */
@Slf4j
@SpringBootTest
public class EventChildFlowTest {

    @Resource
    private RepositoryService repositoryService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;
    @Resource
    private ManagementService managementService;

    /**
     *  <h2>事件子流程</h2>
     *  <hr/>
     *  <p>
     *  &emsp;&emsp;事件子流程是BPMN 2.0中加入的新元素，指通过事件触发的子流程，可以存在于流程级别，或者任何子流程级别。和内嵌子流程类似，事件子流程同样把一
     * 系列的活动组合到一个区域块中，不同之处在于事件子流程不能直接启动，而是被动地由其他事件触发启动。事件子流程可以通过消息事件、信号事件、错误事件、定时器事件、
     * 条件事件、升级事件或变量监听器事件等触发，因此不能在事件子流程中使用空开始事件。开始事件的订阅在包含事件子流程的作用域（流程实例或子流程）创建时就会被创建，
     * 也会在作用域销毁时被删除。事件子流程里面必须有结束节点。
     *  </p>
     *  <p>
     *   &emsp;&emsp;事件子流程可以配置为中断或非中断。中断的子流程会取消当前作用域内的所有执行实例，而非中断的事件子流程将创建一个新的并行执行实例。中断事件子
     * 流程只会被作用域范围内的事件触发一次，而非中断事件子流程可以被触发多次。子流程是否中断由触发事件子流程的开始事件配置。事件子流程不能有任何入口或外出顺序流。
     * 事件子流程是由事件触发的，所以入口顺序流是没有意义的。当事件子流程结束时，要么当前作用域已经结束（中断事件子流程的情况），要么非中断子流程创建的并行执行已经结束。
     *  </p>
     *  <h3>案例演示</h3>
     *  <p>
     *   &emsp;&emsp;主流程是一个扩容流程，用户申请扩容后，由客服进行扩容操作。如果扩容成功，则流程正常结束；如果扩容失败，则流程异常结束，抛出错误信号，事件子流程捕获到
     *   错误信号后被触发，由管理员进行扩容操作。<br/>
     *      <b>流程定义文件：</b>{@link flow/eventSubProcessInMainProcess.bpmn20.xml}<br/>
     *      <b>流程预览图：</b><br/>
     *      <img src="https://cdn4.winhlb.com/2025/05/20/682bf0483f951.png" />
     *  </p>
     **/
    @Test
    public void test() {
        Deployment deploy = repositoryService.createDeployment()
                .name("事件子流程-演示案例")
                .addClasspathResource("flow/eventSubProcessInMainProcess.bpmn20.xml")
                .deploy();
        log.info("部署流程定义：{}", deploy.getId());
        ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getId())
                .singleResult();
        log.info("流程定义编号：{}", procDef.getId());
        //启动流程实例
        ProcessInstance procInst = runtimeService.startProcessInstanceById(procDef.getId());
        ExecutionQuery executionQuery = runtimeService.createExecutionQuery()
                .processInstanceId(procInst.getId());
        //查询执行实例
        List<Execution> executionList1 = executionQuery.list();
        log.info("主流程发起后，执行实例数为{}，分别为：{}", executionList1.size(),
                JSON.toJSONString(executionList1, executionFilter));
        TaskQuery taskQuery = taskService.createTaskQuery()
                .processInstanceId(procInst.getId());
        //查询主流程第一个任务
        Task firstTaskOfMainProcess = taskQuery.singleResult();
        log.info("主流程发起后，流程当前所在的用户任务为：{}",
                firstTaskOfMainProcess.getName());
        //完成主流程第一个任务
        taskService.complete(firstTaskOfMainProcess.getId());
        log.info("完成用户任务：{}", firstTaskOfMainProcess.getName());
        //查询主流程第二个任务
        Task secondTaskOfMainProcess = taskQuery.singleResult();
        log.info("完成用户任务{}后，流程当前所在的用户任务为：{}",
                firstTaskOfMainProcess.getName(), secondTaskOfMainProcess.getName());
        //设置流程变量
        Map<String, Object> varMap = MapUtil.builder(new HashMap<String, Object>())
                .put("operateResult", false)
                .build();
        //完成主流程第二个任务，流程结束，抛出错误信号
        taskService.complete(secondTaskOfMainProcess.getId(), varMap);
        log.info("完成用户任务：{}，发起子流程", secondTaskOfMainProcess.getName());
        //查询执行实例
        List<Execution> executionList2 = executionQuery.list();
        log.info("子流程发起后，执行实例数为{}，分别为：{}", executionList2.size(),
                JSON.toJSONString(executionList2, executionFilter));
        //查询子流程第一个任务
        Task firstTaskOfSubProcess = taskQuery.singleResult();
        log.info("子流程发起后，流程当前所在的用户任务为：{}", firstTaskOfSubProcess.getName());
        //完成子流程第一个任务，子流程结束
        taskService.complete(firstTaskOfSubProcess.getId());
        log.info("完成用户任务：{}，子流程结束", firstTaskOfSubProcess.getName());
        //查询执行实例
        List<Execution> executionList4 = executionQuery.list();
        log.info("主流程结束后，执行实例数为{}，执行实例信息为：{}", executionList4.size(),
                JSON.toJSONString(executionList4, executionFilter));

        /**
         *  演示结果：
         *  2025-05-20 11:03:23.781  INFO 45284 --- [           main] c.b.n.f.e.c.event.EventChildFlowTest     : 部署流程定义：fdb1ea0c-3526-11f0-9143-50ebf6ec8f6d
         * 2025-05-20 11:03:23.786  INFO 45284 --- [           main] c.b.n.f.e.c.event.EventChildFlowTest     : 流程定义编号：fe28046f-3526-11f0-9143-50ebf6ec8f6d
         * 2025-05-20 11:03:24.143  INFO 45284 --- [           main] c.b.n.f.e.c.event.EventChildFlowTest     : 主流程发起后，执行实例数为2，分别为：[{"id":"fe2df7e0-3526-11f0-9143-50ebf6ec8f6d","processDefinitionId":"fe28046f-3526-11f0-9143-50ebf6ec8f6d","processInstanceId":"fe2df7e0-3526-11f0-9143-50ebf6ec8f6d","rootProcessInstanceId":"fe2df7e0-3526-11f0-9143-50ebf6ec8f6d","scope":true},{"activityId":"firstTaskOfMainProcess","id":"fe2e1ef1-3526-11f0-9143-50ebf6ec8f6d","parentId":"fe2df7e0-3526-11f0-9143-50ebf6ec8f6d","processDefinitionId":"fe28046f-3526-11f0-9143-50ebf6ec8f6d","processInstanceId":"fe2df7e0-3526-11f0-9143-50ebf6ec8f6d","rootProcessInstanceId":"fe2df7e0-3526-11f0-9143-50ebf6ec8f6d","scope":false}]
         * 2025-05-20 11:03:24.158  INFO 45284 --- [           main] c.b.n.f.e.c.event.EventChildFlowTest     : 主流程发起后，流程当前所在的用户任务为：申请扩容
         * 2025-05-20 11:03:24.186  INFO 45284 --- [           main] c.b.n.f.e.c.event.EventChildFlowTest     : 完成用户任务：申请扩容
         * 2025-05-20 11:03:24.188  INFO 45284 --- [           main] c.b.n.f.e.c.event.EventChildFlowTest     : 完成用户任务申请扩容后，流程当前所在的用户任务为：客服扩容
         * 2025-05-20 11:03:24.243  INFO 45284 --- [           main] c.b.n.f.e.c.event.EventChildFlowTest     : 完成用户任务：客服扩容，发起子流程
         * 2025-05-20 11:03:24.245  INFO 45284 --- [           main] c.b.n.f.e.c.event.EventChildFlowTest     : 子流程发起后，执行实例数为3，分别为：[{"id":"fe2df7e0-3526-11f0-9143-50ebf6ec8f6d","processDefinitionId":"fe28046f-3526-11f0-9143-50ebf6ec8f6d","processInstanceId":"fe2df7e0-3526-11f0-9143-50ebf6ec8f6d","rootProcessInstanceId":"fe2df7e0-3526-11f0-9143-50ebf6ec8f6d","scope":true},{"activityId":"eventSubProcess","id":"fe6eaa6e-3526-11f0-9143-50ebf6ec8f6d","parentId":"fe2df7e0-3526-11f0-9143-50ebf6ec8f6d","processDefinitionId":"fe28046f-3526-11f0-9143-50ebf6ec8f6d","processInstanceId":"fe2df7e0-3526-11f0-9143-50ebf6ec8f6d","rootProcessInstanceId":"fe2df7e0-3526-11f0-9143-50ebf6ec8f6d","scope":false},{"activityId":"firstTaskOfSubProcess","id":"fe6eaa70-3526-11f0-9143-50ebf6ec8f6d","parentId":"fe6eaa6e-3526-11f0-9143-50ebf6ec8f6d","processDefinitionId":"fe28046f-3526-11f0-9143-50ebf6ec8f6d","processInstanceId":"fe2df7e0-3526-11f0-9143-50ebf6ec8f6d","rootProcessInstanceId":"fe2df7e0-3526-11f0-9143-50ebf6ec8f6d","scope":false}]
         * 2025-05-20 11:03:24.247  INFO 45284 --- [           main] c.b.n.f.e.c.event.EventChildFlowTest     : 子流程发起后，流程当前所在的用户任务为：管理员扩容
         * 2025-05-20 11:03:24.301  INFO 45284 --- [           main] c.b.n.f.e.c.event.EventChildFlowTest     : 完成用户任务：管理员扩容，子流程结束
         * 2025-05-20 11:03:24.303  INFO 45284 --- [           main] c.b.n.f.e.c.event.EventChildFlowTest     : 主流程结束后，执行实例数为0，执行实例信息为：[]
         **/
    }

    SimplePropertyPreFilter executionFilter = new SimplePropertyPreFilter(Execution.class,
            "id", "parentId", "processInstanceId", "processDefinitionId",
            "rootProcessInstanceId", "scope", "activityId", "businessKey");
    SimplePropertyPreFilter jobFilter = new SimplePropertyPreFilter(Job.class,
            "id", "executionId", "duedate", "jobHandlerType", "jobType",
            "processDefinitionId", "processInstanceId", "retries");

    /**
     *  <h2>嵌入式子流程</h2>
     *  <p>
     *      下面看一个事件子流程处于“子流程”级别的示例，如图所示。主流程中用户申请扩容后，进入嵌入式子流程，由客服进行扩容操作。如果扩容成功，则流程正常结束；如果扩容失败，则流程异常结束，
     *  抛出错误信号，嵌入式子流程中的事件子流程捕获到错误事件后触发，由管理员进行扩容操作。<br/>
     *      <b>流程定义文件：</b>{@link flow/eventSubProcessInSub.bpmn20.xml}<br/>
     *      <b>流程预览图：</b><br/>
     *      <img src="https://cdn4.winhlb.com/2025/05/20/682bf3b40e524.png" />
     *
     *      <br/>
     *      <br/>
     *      与上文流程等效的流程还可以下图所示：
     *      <b>流程定义文件：</b>{@link flow/eventSubProcessInBound.bpmn20.xml}<br/>
     *      <b>流程预览图：</b><br/>
     *      <img src="https://cdn4.winhlb.com/2025/05/20/682bf79d6e57f.png" />
     *  </p>
     **/
    @Test
    public void testSub2() {
        Deployment deploy = repositoryService.createDeployment()
                .name("事件嵌入式子流程-演示案例")
                .addClasspathResource("flow/eventSubProcessInSub.bpmn20.xml")
                .deploy();
        log.info("部署流程定义：{}", deploy.getId());
        ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getId())
                .singleResult();
        log.info("流程定义编号：{}", procDef.getId());
        //启动流程实例
        ProcessInstance procInst = runtimeService.startProcessInstanceById(procDef.getId());

        ExecutionQuery executionQuery = runtimeService.createExecutionQuery()
                .processInstanceId(procInst.getId());
        //查询执行实例
        List<Execution> executionList1 = executionQuery.list();
        log.info("主流程发起后，执行实例数为{}，分别为：{}", executionList1.size(),
                JSON.toJSONString(executionList1, executionFilter));
        TaskQuery taskQuery = taskService.createTaskQuery()
                .processInstanceId(procInst.getId());
        //查询主流程第一个任务
        Task firstTaskOfMainProcess = taskQuery.singleResult();
        log.info("主流程发起后，流程当前用户任务为：{}", firstTaskOfMainProcess.getName());
        //完成主流程第一个任务
        taskService.complete(firstTaskOfMainProcess.getId());
        //查询子流程第一个任务
        Task firstTaskOfSubProcess = taskQuery.singleResult();
        log.info("办理完成用户任务{}后，流程当前用户任务点为：{}",
                firstTaskOfMainProcess.getName(), firstTaskOfSubProcess.getName());
        //查询执行实例
        List<Execution> executionList2 = executionQuery.list();
        log.info("子流程发起后，执行实例数为{}，分别为：{}", executionList2.size(),
                JSON.toJSONString(executionList2, executionFilter));
        //设置流程变量
        Map<String, Object> varMap = MapUtil.builder(new HashMap<String, Object>())
                .put("operateResult", false)
                        .build();
        //完成子流程第一个任务，子流程到达错误结束节点，抛出错误信号
        taskService.complete(firstTaskOfSubProcess.getId(), varMap);
        //查询执行实例
        List<Execution> executionList3 = executionQuery.list();
        log.info("事件子流程发起后，执行实例数为{}，分别为：{}", executionList3.size(),
                JSON.toJSONString(executionList3, executionFilter));
        //查询事件子流程第一个任务
        Task firstTaskOfEventSubProcess = taskQuery.singleResult();
        log.info("事件子流程发起后，流程当前用户任务点为：{}",
                firstTaskOfEventSubProcess.getName());
        //完成事件子流程第一个任务，事件子流程结束
        taskService.complete(firstTaskOfEventSubProcess.getId());
        //查询执行实例
        List<Execution> executionList4 = executionQuery.list();
        log.info("主流程结束后，执行实例数为{}，执行实例信息为：{}", executionList4.size(),
                JSON.toJSONString(executionList4, executionFilter));

        /**
         *  演示结果：
         *  2025-05-20 11:21:41.809  INFO 35700 --- [           main] c.b.n.f.e.c.event.EventChildFlowTest     : 部署流程定义：8c53f90c-3529-11f0-9e7c-50ebf6ec8f6d
         * 2025-05-20 11:21:41.812  INFO 35700 --- [           main] c.b.n.f.e.c.event.EventChildFlowTest     : 流程定义编号：eventSubProcessInSub:1:8c9d0fff-3529-11f0-9e7c-50ebf6ec8f6d
         * 2025-05-20 11:21:42.171  INFO 35700 --- [           main] c.b.n.f.e.c.event.EventChildFlowTest     : 主流程发起后，执行实例数为2，分别为：[{"id":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","processDefinitionId":"eventSubProcessInSub:1:8c9d0fff-3529-11f0-9e7c-50ebf6ec8f6d","processInstanceId":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","rootProcessInstanceId":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","scope":true},{"activityId":"firstTaskOfMainProcess","id":"8ca79751-3529-11f0-9e7c-50ebf6ec8f6d","parentId":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","processDefinitionId":"eventSubProcessInSub:1:8c9d0fff-3529-11f0-9e7c-50ebf6ec8f6d","processInstanceId":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","rootProcessInstanceId":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","scope":false}]
         * 2025-05-20 11:21:42.189  INFO 35700 --- [           main] c.b.n.f.e.c.event.EventChildFlowTest     : 主流程发起后，流程当前用户任务为：申请扩容
         * 2025-05-20 11:21:42.250  INFO 35700 --- [           main] c.b.n.f.e.c.event.EventChildFlowTest     : 办理完成用户任务申请扩容后，流程当前用户任务点为：客服扩容
         * 2025-05-20 11:21:42.252  INFO 35700 --- [           main] c.b.n.f.e.c.event.EventChildFlowTest     : 子流程发起后，执行实例数为3，分别为：[{"id":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","processDefinitionId":"eventSubProcessInSub:1:8c9d0fff-3529-11f0-9e7c-50ebf6ec8f6d","processInstanceId":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","rootProcessInstanceId":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","scope":true},{"activityId":"subProcess","id":"8ce20847-3529-11f0-9e7c-50ebf6ec8f6d","parentId":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","processDefinitionId":"eventSubProcessInSub:1:8c9d0fff-3529-11f0-9e7c-50ebf6ec8f6d","processInstanceId":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","rootProcessInstanceId":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","scope":true},{"activityId":"firstTaskOfSubProcess","id":"8ce20849-3529-11f0-9e7c-50ebf6ec8f6d","parentId":"8ce20847-3529-11f0-9e7c-50ebf6ec8f6d","processDefinitionId":"eventSubProcessInSub:1:8c9d0fff-3529-11f0-9e7c-50ebf6ec8f6d","processInstanceId":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","rootProcessInstanceId":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","scope":false}]
         * 2025-05-20 11:21:42.313  INFO 35700 --- [           main] c.b.n.f.e.c.event.EventChildFlowTest     : 事件子流程发起后，执行实例数为4，分别为：[{"id":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","processDefinitionId":"eventSubProcessInSub:1:8c9d0fff-3529-11f0-9e7c-50ebf6ec8f6d","processInstanceId":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","rootProcessInstanceId":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","scope":true},{"activityId":"subProcess","id":"8ce20847-3529-11f0-9e7c-50ebf6ec8f6d","parentId":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","processDefinitionId":"eventSubProcessInSub:1:8c9d0fff-3529-11f0-9e7c-50ebf6ec8f6d","processInstanceId":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","rootProcessInstanceId":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","scope":true},{"activityId":"eventSubProcess","id":"8cee6463-3529-11f0-9e7c-50ebf6ec8f6d","parentId":"8ce20847-3529-11f0-9e7c-50ebf6ec8f6d","processDefinitionId":"eventSubProcessInSub:1:8c9d0fff-3529-11f0-9e7c-50ebf6ec8f6d","processInstanceId":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","rootProcessInstanceId":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","scope":false},{"activityId":"firstTaskOfEventSubProcess","id":"8cee6465-3529-11f0-9e7c-50ebf6ec8f6d","parentId":"8cee6463-3529-11f0-9e7c-50ebf6ec8f6d","processDefinitionId":"eventSubProcessInSub:1:8c9d0fff-3529-11f0-9e7c-50ebf6ec8f6d","processInstanceId":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","rootProcessInstanceId":"8ca77040-3529-11f0-9e7c-50ebf6ec8f6d","scope":false}]
         * 2025-05-20 11:21:42.314  INFO 35700 --- [           main] c.b.n.f.e.c.event.EventChildFlowTest     : 事件子流程发起后，流程当前用户任务点为：管理员扩容
         * 2025-05-20 11:21:42.364  INFO 35700 --- [           main] c.b.n.f.e.c.event.EventChildFlowTest     : 主流程结束后，执行实例数为0，执行实例信息为：[]
         **/
    }
}
